﻿using System;
using System.Data.Services.Client;
using System.Globalization;
using System.Linq;
using System.Windows;
using Tfs.OnTheRoad.Commands;
using Tfs.OnTheRoad.Helpers;
using Tfs.OnTheRoad.Model;
namespace Tfs.OnTheRoad.ViewModel
{
    /// <summary>
    /// Settings ViewModel
    /// </summary>
    public class SettingsViewModel : BaseViewModel
    {      
        public NavigateToHelpCommand NavigateToHelp
        { 
            get; 
            private set; 
        }

        public TestSettingsCommand TestSettings
        {
            get;
            private set;
        }

        public SettingsViewModel()
            : base()
        {
            ProfileName = "CodePlex TFS";
            IsDefault = true;
            Domain = string.Empty;
            UserName = string.Empty;
            Password = string.Empty;
            TfsOdataEndPoint = "https://codeplexodata.cloudapp.net";
            ProjectCollection = string.Empty;

            PageTitle = "Settings";
            _testResults = string.Empty;
            TestSettings = new TestSettingsCommand(this);
            NavigateToHelp = new NavigateToHelpCommand(this);
        }

        

        private string _testResults;

        public string TestResults
        {
            get { return _testResults; }
            set
            {
                _testResults = value;
                this.RaisePropertyChanged("TestResults");
            }
        }


        private bool _isDefault;
        public bool IsDefault
        {
            get { return _isDefault; }
            set
            {
                _isDefault = value;
                this.RaisePropertyChanged("IsDefault");
            }
        }
        
        private string _profileName;
        public string ProfileName
        {
            get { return _profileName; }
            set
            {
                _profileName = value;
                this.RaisePropertyChanged("ProfileName");
            }
        }

        private string _domain;
        public string Domain
        {
            get { return _domain; }
            set
            {
                _domain = value;
                this.RaisePropertyChanged("Domain");
                this.RaisePropertyChanged("CanTest"); 
            }
        }
        
        private string _userName;
        public string UserName
        {
            get { return _userName; }
            set 
            {
                _userName = value;
                this.RaisePropertyChanged("UserName");
                this.RaisePropertyChanged("CanTest"); 
            }
        }

        private string _password;
        public string Password
        {
            get { return _password; }
            set
            {
                _password = value;
                this.RaisePropertyChanged("Password");
                this.RaisePropertyChanged("CanTest");
            }
        }

        private string _tfsOdataEndPoint;
        public string TfsOdataEndPoint
        {
            get { return _tfsOdataEndPoint; }
            set
            {
                _tfsOdataEndPoint = value;
                this.RaisePropertyChanged("TfsOdataEndPoint");
                this.RaisePropertyChanged("FullAddress");
                this.RaisePropertyChanged("CanTest");
            }
        }

        private string _projectCollection;
        public string ProjectCollection
        {
            get { return _projectCollection; }
            set
            {
                _projectCollection = value;
                this.RaisePropertyChanged("ProjectCollection");
                this.RaisePropertyChanged("FullAddress");
                this.RaisePropertyChanged("CanTest");
            }
        }

        private bool _logingIn;
        public bool LogingIn
        {
            get { return _logingIn; }
            set
            {
                _logingIn = value;
                this.RaisePropertyChanged("LogingIn");
            }
        }
       
        public bool CanTest     
        {
            get
            {
                return !string.IsNullOrEmpty(this.UserName)
                        && !string.IsNullOrEmpty(this.ProfileName)
                        && !string.IsNullOrEmpty(this.Domain)
                        && !string.IsNullOrEmpty(this.Password)
                        && !string.IsNullOrEmpty(this.TfsOdataEndPoint)
                        && !string.IsNullOrEmpty(this.ProjectCollection);
            }
        }

        public string FullAddress
        {
            get {
                if (_tfsOdataEndPoint == null || _projectCollection == null) return string.Empty;
                string odataEndPoint = _tfsOdataEndPoint;
                if (!odataEndPoint.EndsWith("/"))
                    odataEndPoint += "/";
                return odataEndPoint + _projectCollection;
            }
        }
        
        private bool CheckEndPoint(out string errorMessage)
        {
            errorMessage = string.Empty;
            
            Uri tfsServerUri;
            if (!Uri.TryCreate(FullAddress, UriKind.Absolute, out tfsServerUri))
            {
                errorMessage = "The OData service for Team Foundation Server endpoint URL is not valid.";
                return false;
            }

            if ((tfsServerUri.Scheme != Uri.UriSchemeHttp) && (tfsServerUri.Scheme != Uri.UriSchemeHttps))
            {
                errorMessage = "The Uri scheme used is not supported. Please use HTTP or HTTPS schemes.";
                return false;
            }
            return true;
        }


        public void Login(Action<LoginResult> callback)
        {
            var errorMessage = string.Empty;
            if (!this.CheckEndPoint(out errorMessage))
            {
                callback.Invoke(new LoginResult { IsAuthenticated = false, Description = errorMessage });
                return;
            }
            
            this.LogingIn = true;
            var context = App.CreateTfsDataServiceContext(this);
            var requestUri = new Uri(string.Format(CultureInfo.InvariantCulture, "{0}/Projects?$top=1&$select=Name", this.FullAddress), UriKind.Absolute);

            context.BeginExecute<Project>(
                requestUri,
                r =>
                {
                    try
                    {
                        var result = context.EndExecute<Project>(r) as QueryOperationResponse<Project>;
                        if (result != null)
                        {
                            
                            //Before save, if the profile that was modified is set to be the default, we should set the isDefault of all other loaded Settings
                            if (_isDefault)
                            {
                                var allButThis = from item in App.SettingsViewModels
                                                 where item != this
                                                 select item;
                                Deployment.Current.Dispatcher.BeginInvoke(() =>
                                {
                                foreach (var item in allButThis)
                                    item.IsDefault = false;
                                });
                            }
                            //Being added?
                            if (!App.SettingsViewModels.Contains(this))
                                Deployment.Current.Dispatcher.BeginInvoke(() =>
                                {
                                    App.SettingsViewModels.Add(this);
                                    App.SettingsViewModel = this;
                                });
                                
                            // Save the valid credentials in the Isolated Storage
                            Deployment.Current.Dispatcher.BeginInvoke(() =>
                            {
                                SettingsStorageHelper.ClearSettings(App.IsolatedStorageFileName);
                                SettingsStorageHelper.SaveSettings(App.SettingsViewModels, App.IsolatedStorageFileName);
                            });
                            this.DispatchResult(callback, new LoginResult { IsAuthenticated = true, Description = string.Empty });
                        }
                    }
                    catch (Exception ex)
                    {
                        Exception dataServiceException;
                        var result = new LoginResult { IsAuthenticated = false, Description = ex.Message };

                        if (DataServiceExceptionHelper.TryParse(ex, out dataServiceException))
                        {
                            result.Description = dataServiceException.Message;
                        }
                        else if (ex.InnerException != null)
                        {
                            if (ex.InnerException is System.Data.Services.Client.DataServiceClientException)
                                result.Description = returnHtmlDefaultErrorCodes(ex.InnerException as System.Data.Services.Client.DataServiceClientException);
                            else
                                result.Description = ex.InnerException.Message;
                        }
                        this.DispatchResult(callback, result);
                    }
                },
                null);
        }

        private string returnHtmlDefaultErrorCodes(System.Data.Services.Client.DataServiceClientException exceptionToParse)
        {
            string toReturn = exceptionToParse.ToString();            
            switch ((System.Net.HttpStatusCode)exceptionToParse.StatusCode)
            {
                case System.Net.HttpStatusCode.Unauthorized:
                    toReturn = "Unauthorized - Username or password are invalid";
                    break;
                default:
                    break;
            }
            return toReturn;
        }
        private void DispatchResult(Action<LoginResult> callback, LoginResult result)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                this.LogingIn = false;
                callback.Invoke(result);
            });
        }

        public struct LoginResult
        {
            public bool IsAuthenticated { get; set; }

            public string Description { get; set; }
        }
    }
}
